#include "time_wheel.h"

namespace qio {

TimeoutHandle::~TimeoutHandle() QIO_NOEXCEPT {  // NOLINT
}

TimeWheel::TimeWheel(EventLoop *loop) QIO_NOEXCEPT : loop_(loop),
                                                     timeout_ms_(0),
                                                     timer_(nullptr),
                                                     bucket_queue_() {
  assert(loop_ != nullptr);
  bucket_queue_.emplace_back(Element{});
}

TimeWheel::~TimeWheel() QIO_NOEXCEPT {
  if (timer_) {
    timer_->Stop();
  }
}

void TimeWheel::AddEntry(const TimeWheel::Entry &entry) QIO_NOEXCEPT {
  assert(!bucket_queue_.empty());
  auto &last = bucket_queue_.back();
  last.emplace(entry);
}

void TimeWheel::StartTimeout(TimeoutMs timeout) QIO_NOEXCEPT {
  timeout_ms_ = timeout;
  if (timer_ != nullptr) {
    timer_->Stop();
    timer_ = nullptr;
  }
  if (timeout == 0) {
    return;
  }
  static constexpr unsigned wheel_block_count = 5;
  auto each_block_timeout = timeout_ms_ / wheel_block_count;
  timer_ = loop_->RunEvery(each_block_timeout, [this](Timer *timer) {
    if (wheel_block_count == bucket_queue_.size()) {
      bucket_queue_.pop_front();
    }
    bucket_queue_.emplace_back(Element{});
  });
}

}  // namespace qio